<template>
  <div
    class="form-widget-container"
    id="form-widget-content"
    @contextmenu.prevent="showMenu($event)"
    @click.prevent="hideMenu"
  >
    <el-form
      class="full-height-width widget-form"
      :label-position="labelPosition"
      :size="size"
      :validate-on-rule-change="false"
    >
      <div v-if="designer.widgetList.length === 0" class="no-widget-hint">
        {{ i18nt("designer.noWidgetHint") }}
      </div>
      <draggable
        :list="designer.widgetList"
        v-bind="{ group: 'dragGroup', ghostClass: 'ghost', animation: 300 }"
        handle=".drag-handler"
        @add="onDragAdd"
        @update="onDragUpdate"
        :move="checkMove"
      >
        <transition-group name="fade" tag="div" class="form-widget-list">
          <template v-for="(widget, index) in designer.widgetList">
            <template v-if="'container' === widget.category">
              <component
                :is="getWidgetName(widget)"
                :widget="widget"
                :designer="designer"
                :key="widget.id"
                v-bind.sync="$data"
                :fatherData="$data"
                :parent-list="designer.widgetList"
                :index-of-parent-list="index"
                :parent-widget="null"
              >
              </component>
            </template>
            <template v-else>
              <component
                :is="getWidgetName(widget)"
                :dataSourceMapData="dataSourceMapData"
                :field="widget"
                :designer="designer"
                :key="widget.id"
                v-bind.sync="$data"
                :fatherData="$data"
                :parent-list="designer.widgetList"
                :index-of-parent-list="index"
                :parent-widget="null"
                :design-state="true"
              >
              </component>
            </template>
          </template>
        </transition-group>
      </draggable>
    </el-form>
    <!--右键菜单-聊天内容复制-->
    <div
      class="rightMenu"
      v-if="isShowMenu"
      :style="{ left: Menu_left + 'px', top: Menu_top + 'px' }"
    >
      <el-card class="Menu_card">
        <div class="Menu_card_item" @click="onCopy">复制已选组件</div>
        <div
          class="Menu_card_item"
          v-if="showAddEmptyContainer"
          @click="addContainer"
        >
          包装已选容器
        </div>
        <div class="Menu_card_item" @click="unSelect">取消所有选择</div>
        <div class="Menu_card_item" @click="saveSelfComponent">
          保存为组件(已选{{ designer.selfComponent.length }}个)
        </div>
        <div class="Menu_card_item" @click="saveSelfTemplate">保存为模板</div>
        <div class="Menu_card_item" @click="pasteContent">粘贴</div>
        <!-- <div class="Menu_card_item no_border">更多</div> -->
      </el-card>
    </div>

    <el-dialog
      :visible.sync="dialogVisible"
      append-to-body
      :title="dialogType === 'template' ? '新增自定义模板' : '新增自定义组件'"
    >
      <el-form
        ref="dialogForm"
        :model="dialogForm"
        label-width="80px"
        :rules="rules"
      >
        <el-form-item label="中文名" prop="nameCn">
          <el-input v-model="dialogForm.nameCn"></el-input>
        </el-form-item>
        <el-form-item label="英文名" prop="nameEn">
          <el-input v-model="dialogForm.nameEn"></el-input>
        </el-form-item>
        <el-form-item label="组件编码" prop="code">
          <el-input v-model="dialogForm.code"></el-input>
        </el-form-item>
        <el-form-item label="中文描述" prop="describeCn">
          <el-input v-model="dialogForm.describeCn"></el-input>
        </el-form-item>
        <el-form-item label="英文描述" prop="describeEn">
          <el-input v-model="dialogForm.describeEn"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveConfirm">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import Draggable from "vuedraggable";
import "@/components/form-designer/form-widget/container-widget/index";
import FieldComponents from "@/components/form-designer/form-widget/field-widget/index";
import DataComponents from "@/components/form-designer/form-widget/data-widget/index";
import LayoutComponents from "@/components/form-designer/form-widget/layout-widget/index";
import i18n from "@/utils/i18n";
import { copyToClipboard, generateId, deepClone } from "@/utils/util";
import * as api from "@/api/applicationManage/applicationManage";
import html2canvas from "html2canvas";

export default {
  name: "VFormWidget",
  componentName: "VFormWidget",
  mixins: [i18n],
  components: {
    Draggable,
    ...FieldComponents,
    ...DataComponents,
    ...LayoutComponents,
  },
  props: {
    designer: Object,
    formConfig: Object,
    refreshTemplate: Function,
    refreshComponent: Function,
    optionData: {
      //prop传入的选项数据
      type: Object,
      default: () => ({}),
    },
    globalDsv: {
      type: Object,
      default: () => ({}),
    },
    dataSourceMapData: {
      type: Object,
      default: () => {
        return {};
      },
    },
    script: {
      type: Object,
      default: () => {
        return { data: {}, methods: {} };
      },
    },
  },
  provide() {
    return {
      refList: this.widgetRefList,
      formConfig: this.formConfig,
      getGlobalDsv: () => this.globalDsv, // 全局数据源变量
      globalOptionData: this.optionData,
      getOptionData: () => this.optionData,
      globalModel: {
        formModel: this.formModel,
      },
    };
  },
  inject: ["getDesignerConfig"],
  data() {
    return {
      dialogVisible: false,
      dialogForm: {},
      rules: {
        nameCn: [
          { required: true, message: "请输入中文名称", trigger: "blur" },
        ],
        nameEn: [
          { required: true, message: "请输入英文名称", trigger: "blur" },
        ],
        code: [
          { required: true, message: "请输入组件编码", trigger: "blur" },
          {
            pattern: "^[A-Za-z][A-Za-z0-9_]{1,29}$",
            message: "请输入正确组件编码",
          },
        ],
      },

      formModel: {},
      widgetRefList: {},
      isShowMenu: false, // 是否显示右侧菜单
      Menu_item: "", // 复制的内容
      Menu_top: 0,
      Menu_left: 0,
      dialogType: "component",
      imageUrl: "",
      ...this.script.data,
    };
  },
  computed: {
    labelPosition() {
      if (
        !!this.designer.formConfig &&
        !!this.designer.formConfig.labelPosition
      ) {
        return this.designer.formConfig.labelPosition;
      }
      return "left";
    },

    size() {
      if (!!this.designer.formConfig && !!this.designer.formConfig.size) {
        return this.designer.formConfig.size;
      }
      return "small";
    },

    customClass() {
      return this.designer.formConfig.customClass || "";
    },
    showAddEmptyContainer() {
      if (
        this.designer.selectedWidget &&
        this.designer.selectedWidget.category === "container"
      ) {
        return true;
      }
      return false;
    },
  },
  created() {
    Object.assign(this, this.script.methods);
    this.designer.initDesigner(!!this.getDesignerConfig().resetFormJson);
    this.designer.loadPresetCssCode(this.getDesignerConfig().presetCssCode);
    this.addCloseMenu();
  },
  mounted() {
    this.disableFirefoxDefaultDrop();
    this.designer.registerFormWidget(this);
  },
  methods: {
    saveSelfComponent() {
      this.dialogType = "component";
      this.dialogVisible = true;
    },
    saveSelfTemplate() {
      this.dialogType = "template";
      this.isShowMenu = false;
      const boxID = "form-widget-content"; //编辑器容器id
      const that = this;
      this.$nextTick(() => {
        let dom = document.getElementById(boxID);
        html2canvas(dom).then((canvas) => {
          const imgData = canvas.toDataURL("image/png");
          var dataURLtoBlob = function (dataUrl) {
            var arr = dataUrl.split(","),
              mime = arr[0].match(/:(.*?);/)[1],
              bstr = atob(arr[1]),
              n = bstr.length,
              u8arr = new Uint8Array(n);
            while (n--) {
              u8arr[n] = bstr.charCodeAt(n);
            }
            return new Blob([u8arr], { type: mime });
          };
          const blobData = dataURLtoBlob(imgData);
          const formData = new FormData();
          formData.append("file", blobData);
          formData.append("suffix", "png");
          api.upload(formData).then((res) => {
            that.imageUrl = res.data.data;
          });
        });
      });
      this.dialogVisible = true;
    },
    getFormJson() {
      return {
        widgetList: deepClone(this.designer.widgetList),
        formConfig: deepClone(this.designer.formConfig),
        pageScript: deepClone(this.designer.pageScript),
        dataSource: deepClone(this.designer.dataSource),
        templateScript: deepClone(this.designer.templateScript),
      };
    },
    /**
     * 保存自定义模板
     * */
    saveTemplate() {
      const that = this;
      this.$refs.dialogForm.validate((f) => {
        if (f) {
          let applicationId = localStorage.getItem("appId");

          const paramsData = {
            ...this.dialogForm,
            applicationId,
            filePath: this.imageUrl,
            json: JSON.stringify(this.getFormJson()),
          };
          api.templateAdd(paramsData).then((res) => {
            that.$message.success("保存成功");
            that.dialogVisible = false;
            that.designer.selfComponent = [];
            that.imageUrl = "";
            that.dialogForm = {};
            that.refreshTemplate();
          });
        }
      });
    },
    /**
     * 保存自定义组件
     * */
    saveComponent() {
      let ids = this.designer.selfComponent.map((i) => i.id);
      if (!ids || ids.length === 0) {
        this.$message.error("请按住CTRL(COMMAND)选择组件");
        return;
      }
      let widgetList = this.deepCopy(this.designer.widgetList);
      // 被选中的组件的父类组件集合
      let widgetListItem = [];
      /**
       * 递归 组装为树形结构
       * */
      let recursion = (data, pObj) => {
        if (data && data.length > 0) {
          for (let i = 0; i < data.length; i++) {
            let item = data[i];
            if (item.category === "container") {
              if (item.type === "grid") {
                recursion(item.cols, item);
              }
              if (item.type === "tab") {
                recursion(item.tabs, item);
              }

              if (
                ["grid-col", "tab-pane", "el-dialog", "el-drawer","box-container"].includes(
                  item.type
                )
              ) {
                recursion(item.widgetList, item);
              }
            }

            if (pObj) {
              item.parentId = pObj.id;
            } else {
              item.parentId = 0;
            }

            let it = this.deepCopy(item);
            if (it.type === "grid") {
              it.cols = [];
            }
            if (it.type === "grid-col") {
              it.widgetList = [];
            }
            widgetListItem.push(it);
          }
        }
      };
      recursion(widgetList, false);

      /**
       * 递归取得最外层 id
       * */
      if (ids.length > 0) {
        let l = (data) => {
          if (data && data.length > 0) {
            for (let i = 0; i < data.length; i++) {
              let item = data[i];
              if (ids.includes(item.id)) {
                ids.push(item.parentId);
              }
            }
          }
        };
        l(widgetListItem);
      }

      let y = [];
      widgetListItem.forEach((item) => {
        if (ids.includes(item.id)) {
          y.push(item);
        }
      });

      /**
       * 递归 将需要的数据组装为结构树
       * */
      function buildTree(arr, parentId = 0) {
        const tree = [];

        for (let i = 0; i < arr.length; i++) {
          if (arr[i].parentId === parentId) {
            const children = buildTree(arr, arr[i].id);

            if (children.length) {
              arr[i].children = children;
            }

            tree.push(arr[i]);
          }
        }

        return tree;
      }

      let tree = buildTree(y);

      let tr = this.deepCopy(tree);

      /**
       * 递归 删除children数组，将数据放入指定数组
       * */
      let lp = (data) => {
        if (data && data.length > 0) {
          for (let i = 0; i < data.length; i++) {
            let item = data[i];
            if (item.category === "container") {
              if (item.type === "grid") {
                item.cols = item.children;
                delete item.children;
                lp(item.cols);
              }

              if (item.type === "tab") {
                item.tabs = item.children;
                delete item.children;
                lp(item.tabs);
              }

              if (
                ["grid-col", "tab-pane", "el-dialog", "el-drawer"].includes(
                  item.type
                )
              ) {
                item.widgetList = item.children;
                delete item.children;
                lp(item.widgetList);
              }
            }
          }
        }
      };
      lp(tr);
      const that = this;
      this.$refs.dialogForm.validate((f) => {
        if (f) {
          let applicationId = localStorage.getItem("appId");

          let obj = {};
          obj["templateScript"] = this.designer.pageScript;
          Object.assign(obj["templateScript"], {
            dataSource: this.designer.dataSource,
          });
          const paramsData = {
            ...this.dialogForm,
            applicationId,
            // filePath: this.imageUrl,
            // jsonConfig: JSON.stringify(tr),
            json: JSON.stringify({
              widgetList: tr,
              ...obj,
            }),
          };
          api.componentAdd(paramsData).then(() => {
            that.$message.success("保存成功");
            that.dialogVisible = false;
            that.designer.selfComponent = [];
            that.imageUrl = "";
            that.dialogForm = {};
            that.refreshComponent();
          });
        }
      });
    },
    saveConfirm() {
      if (this.dialogType === "template") {
        this.saveTemplate();
      } else {
        this.saveComponent();
      }
    },
    /**
     * 获取组件名
     * @param widget 组件json对象
     * */
    getWidgetName(widget) {
      return widget.type + "-widget";
    },

    /**
     * 禁用Firefox默认拖拽搜索功能
     * */
    disableFirefoxDefaultDrop() {
      let isFirefox =
        navigator.userAgent.toLowerCase().indexOf("firefox") !== -1;
      if (isFirefox) {
        document.body.ondrop = function (event) {
          event.stopPropagation();
          event.preventDefault();
        };
      }
    },

    /**
     * 拖拽添加内容
     * @param evt 拖拽元素 属性
     * */
    onDragAdd(evt) {
      const newIndex = evt.newIndex;
      if (this.designer.widgetList[newIndex]) {
        this.designer.setSelected(this.designer.widgetList[newIndex]);
      }
      // 拖入数据容器
      if(this.designer.selectedWidget && ['data-view','data-grid'].indexOf(this.designer.selectedWidget.type) > -1){
          this.designer.addDataScript(this.designer.selectedWidget)
      }
      this.designer.emitHistoryChange();
      this.designer.emitEvent("field-selected", null);
    },

    /**
     * 更新拖拽组件
     * 在VueDraggable内拖拽组件发生位置变化时会触发update，未发生组件位置变化不会触发
     * */
    onDragUpdate() {
      this.designer.emitHistoryChange();
    },

    checkMove(evt) {
      return this.designer.checkWidgetMove(evt);
    },

    /**
     * 获取form表单的绑定值
     * */
    getFormData() {
      return this.formModel;
    },

    /**
     * 获取指定组件的ref
     * */
    getWidgetRef(widgetName, showError = false) {
      let foundRef = this.widgetRefList[widgetName];
      if (!foundRef && !!showError) {
        this.$message.error(this.i18nt("render.hint.refNotFound") + widgetName);
      }
      return foundRef;
    },

    /**
     * 获取选中组件的ref
     * */
    getSelectedWidgetRef() {
      let wName = this.designer.selectedWidgetName;
      return this.getWidgetRef(wName);
    },

    /**
     * 删除所有ref
     * */
    clearWidgetRefList() {
      Object.keys(this.widgetRefList).forEach((key) => {
        delete this.widgetRefList[key];
      });
    },

    /**
     * 删除选中的ref
     * */
    deleteWidgetRef(widgetRefName) {
      delete this.widgetRefList[widgetRefName];
    },

    /**
     * 粘贴已复制组件
     * */
    pasteContainer(origin) {
      let newCon = { ...origin };
      for (let key in newCon) {
        // 判断是不是数组
        if (newCon[key] instanceof Array) {
          newCon[key] = newCon[key].map((v) => {
            return {
              ...this.pasteContainer(v),
            };
          });
        }
      }
      newCon.id = newCon.type + generateId();
      return newCon;
    },

    /**
     * 粘贴已复制组件
     * */
    pasteContent() {
      const pasteC = localStorage.getItem("widget__list__copy");
      this.isShowMenu = false;
      this.Menu_item = "";
      if (pasteC) {
        let newWidget = JSON.parse(pasteC);

        // 解决id重复的问题
        if (newWidget.category === "container") {
          newWidget = this.pasteContainer(newWidget);
        }

        this.designer.widgetList.push({
          ...newWidget,
          id: newWidget.type + generateId(),
        });
      }
    },

    /**
     * 复制组件
     * */
    onCopy(e) {
      if (
        this.designer.selectedWidget &&
        this.designer.selectedWidget.type === "grid-col"
      ) {
        this.$message("栅格列不可复制");
        return;
      }
      if (!this.designer.selectedWidget.id) {
        return;
      }

      copyToClipboard(
        JSON.stringify(this.designer.selectedWidget),
        e,
        this.$message,
        this.i18nt("designer.hint.copyJsonSuccess"),
        this.i18nt("designer.hint.copyJsonFail"),
        () => {
          localStorage.setItem(
            "widget__list__copy",
            JSON.stringify(this.designer.selectedWidget)
          );
        }
      );
    },
    addContainer() {
      this.designer.addContainer();
    },
    addCloseMenu() {
      // 添加监听器，用于其他位置点击时，关闭打开的右键菜单,并清空获取的key
      document.addEventListener("click", () => {
        this.isShowMenu = false;
        this.Menu_item = "";
      });
      // 添加监听器，用于点击菜单内按钮时，关闭打开的右键菜单,并清空获取的key
      document.addEventListener("mousedown", (e) => {
        const { button } = e;
        if (button === 2) {
          this.isShowMenu = false;
          this.Menu_item = "";
        }
      });
    },

    hideMenu() {
      this.isShowMenu = false;
      this.designer.selectedWidget = null;
    },

    // 右键菜单-聊天内容-事件
    showMenu(e) {
      console.log('this.designer=========>',this.designer)
      this.isShowMenu = true;
      // 定位
      this.Menu_top = e.pageY;
      this.Menu_left = e.pageX;
    },

    unSelect() {
      this.designer.selectedId = null;
      this.designer.selectedIdArr = [];
      this.designer.selfComponent = [];
      this.designer.selectedWidgetName = null;
      this.designer.selectedWidget = {}; //this.selectedWidget = null
      this.designer.selectedWidgetList = []; //this.selectedWidget = null
    },
  },
};
</script>

<style lang="scss" scoped>
.container-scroll-bar {
  ::v-deep .el-scrollbar__wrap,
  ::v-deep .el-scrollbar__view {
    overflow-x: hidden;
  }
}

.form-widget-container {
  padding: 10px;
  background: #f1f2f3;

  overflow-x: hidden;
  overflow-y: auto;

  .el-form.full-height-width {
    height: 100%;
    padding: 3px;
    background: #ffffff;

    .no-widget-hint {
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
      font-size: 18px;
      color: #999999;
    }

    .form-widget-list {
      height: calc(100vh - 68px);
      padding: 10px;
      overflow-x: hidden;
      overflow-y: auto;
      box-sizing: border-box;

      &::-webkit-scrollbar {
        width: 4px;
      }
    }
  }

  .el-form.PC-layout {
    //
  }

  .el-form.Pad-layout {
    margin: 0 auto;
    max-width: 960px;
    border-radius: 15px;
    box-shadow: 0 0 1px 10px #495060;
  }

  .el-form.H5-layout {
    margin: 0 auto;
    width: 420px;
    border-radius: 15px;
    //border-width: 10px;
    box-shadow: 0 0 1px 10px #495060;
  }

  .el-form.widget-form ::v-deep .el-row {
    padding: 2px;
    border: 1px dashed rgba(170, 170, 170, 0.75);
  }
}

.grid-cell {
  min-height: 30px;
  border-right: 1px dotted #cccccc;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}

.fade-enter,
.fade-leave-to {
  opacity: 0;
}

/*右键菜单css样式*/
.rightMenu {
  position: fixed;
  z-index: 99999;
}

.Menu_card_item {
  font-size: 14px;
  padding: 10px 20px;
  cursor: pointer;
  border-bottom: 1px solid #ccc;

  &.no_border {
    border: none;
  }
}

.rightMenu {
  ::v-deep .el-card__body {
    padding: 0;
  }
}

.rightMenu .el-button {
  border: 0;
  padding: 12px 30px;
}
</style>
